package com.xuanyue.db.xuan;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CodePointCharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

import com.xuanyue.db.xuan.antlr.impl.ParseTreeE;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Lexer;
import com.xuanyue.db.xuan.antlr.v2.BitQV2Parser;
import com.xuanyue.db.xuan.antlr.v2.function.ListObjectContainsFunction;
import com.xuanyue.db.xuan.antlr.v2.impl.BitQV2ListenerImpl;
import com.xuanyue.db.xuan.antlr.v2.impl.ERRORCheckorV2;
import com.xuanyue.db.xuan.antlr.v2.impl.ProofreaderListenerImplV2;
import com.xuanyue.db.xuan.core.db.ColumnMetaV2;
import com.xuanyue.db.xuan.core.db.DBMetaV2;
import com.xuanyue.db.xuan.core.db.IXyDBV2;
import com.xuanyue.db.xuan.core.db.TableMetaV2;
import com.xuanyue.db.xuan.core.db.XyDBV2;
import com.xuanyue.db.xuan.core.exception.SQLException;
import com.xuanyue.db.xuan.core.index.AcceleraterBitIndex;
import com.xuanyue.db.xuan.core.table.IBitIndex;
import com.xuanyue.db.xuan.core.table.IColumn;
import com.xuanyue.db.xuan.core.table.IXyTable;
import com.xuanyue.db.xuan.core.table.expr.ExprValue;
import com.xuanyue.db.xuan.core.table.expr.IFunctionExecutor;
import com.xuanyue.db.xuan.core.task.Accelerater;
import com.xuanyue.db.xuan.core.task.X2YEXTThreadPoolExecutor;
import com.xuanyue.db.xuan.core.task.X2YEXTThreadPoolExecutor.NothingRejectedExecutionHandler;
import com.xuanyue.db.xuan.core.tools.LruCache;

public class SeachContextV2 {
	private static IXyDBV2 db = new XyDBV2();
	private static X2YEXTThreadPoolExecutor exe;
//	private ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
	private static Map<String,ParseTreeE> treeCache = Collections.synchronizedMap(new LruCache<String,ParseTreeE>(100));
	private static String treeLock = "treeLock";
	
	private static Map<String,IFunctionExecutor<? extends IColumn>> baseFunctionExecutorList = new HashMap<>();
	
	
	
	static {
		exe = new X2YEXTThreadPoolExecutor(40, 80, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10),new NothingRejectedExecutionHandler());
	
		baseFunctionExecutorList.put("list_contains", new ListObjectContainsFunction());
	}
	
	public static IFunctionExecutor<? extends IColumn> getFunction(String name){
		return baseFunctionExecutorList.get(name);
	}
	
	public static IXyTable getTable(String name) {
		return db.getTable(name);
	}

	public static IXyTable createTable(TableMetaV2 tableMetaV2) {
		return db.createTable(tableMetaV2);
	}
	
	private static ParseTreeE getV2(ParseTreeWalker walker,String sql) {
		ParseTreeE tree = treeCache.get(sql);
		if(tree == null) {
			synchronized (treeLock) {
				tree = treeCache.get(sql);
				if(tree == null) {
					CodePointCharStream cpcs = CharStreams.fromString( sql );
			        //用 cpcs 构造词法分析器 lexer，词法分析的作用是产生记号
			        BitQV2Lexer lexer = new BitQV2Lexer(cpcs);
			        //用词法分析器 lexer 构造一个记号流 tokens
			        CommonTokenStream tokens = new CommonTokenStream(lexer);
			        //再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作
			        BitQV2Parser parser = new BitQV2Parser(tokens);
			        
			        parser.removeErrorListeners();
			        ERRORCheckorV2 check = new ERRORCheckorV2(false);
			        parser.addErrorListener(check);
			        
			        
			        //最终调用语法分析器的规则 prog，完成对表达式的验证
			        tree = new ParseTreeE();
			        tree.setTree(parser.bitQ());
			        if(check.isSuccess()) {
			        	tree.setParallel(lexer.getParallel());
					    treeCache.put(sql, tree);
			        }else {
			        	throw new SQLException(check.getMsg());
			        }
				}
			}
		}
		return tree;
	}
	
	@SuppressWarnings("unchecked")
	public static <T extends IColumn> IFunctionExecutor<T> getBaseFunctionExecutor(String fn){
		return (IFunctionExecutor<T>)baseFunctionExecutorList.get(fn);
	}
	
	public static ExprValue exeSql(String sql) {
		return exeSql(sql,null);
	}
	public static ExprValue exeSql(String sql,ExprValue parameters) {
		ParseTreeWalker walker = new ParseTreeWalker();
		ParseTreeE tree = getV2(walker, sql);
		ProofreaderListenerImplV2 evalByListener = new ProofreaderListenerImplV2();
		evalByListener.setParameters(parameters);
		walker.walk(evalByListener, tree.getTree());
		tree.setMaxSource(evalByListener.getMaxSource());
		BitQV2ListenerImpl l2 = new BitQV2ListenerImpl(tree.getMaxSource());
		if(parameters!=null) {
			l2.setParameters(parameters);
		}
		walker.walk(l2, tree.getTree());
		return l2.getResult();
	}
	
	public static void init(String dataPath) {
		db.init(dataPath);
		db.load();
	}
	public static void init(DBMetaV2 dbm) {
		db.init(dbm);
		db.load();
	}
	/**
	 * 获得一条任务线程
	 * @return
	 * @throws InterruptedException
	 * @author 解观海
	 * @date 2021年1月12日
	 */
	public static Accelerater getAccelerate() throws InterruptedException {
		return new Accelerater(exe);
	}
	/**
	 * bit向量封装为多线程模式
	 * @param workers
	 * @param accelerate
	 * @return
	 * @author 解观海
	 * @date 2021年1月12日
	 */
	public static List<IBitIndex> toAccelerateEncapsulation(List<IBitIndex> workers,Accelerater accelerate){
		List<IBitIndex> r = new ArrayList<>();
		for(IBitIndex worker:workers) {
			r.add( new AcceleraterBitIndex(accelerate, worker) );
		}
		return r;
	}
	/**
	 * 多线程模式 的bit向量 还原
	 * @param workers
	 * @return
	 * @author 解观海
	 * @date 2021年1月12日
	 */
	public static List<IBitIndex> unpacke(List<IBitIndex> workers){
		List<IBitIndex> r = new ArrayList<>();
		for(IBitIndex e:workers) {
			r.add( ((AcceleraterBitIndex)e).getWorker() );
		}
		return r;
	}

	public static ReadLock getReadLockOfMeta() {
		return db.getReadLockOfMeta();
	}
	public static WriteLock getWriteLockOfMeta() {
		return db.getWriteLockOfMeta();
	}
	
	public static void dropColumn(String name,String cname) {
		db.dropColumn(name, cname);
	}
	public static void addColumn(String name,ColumnMetaV2 cmV2) {
		db.addColumn(name, cmV2);
	}
	/**
	 * 
	 * @param tableName 表名
	 * @param con  column old name  原始列名称
	 * @param cmV2
	 * @author 解观海
	 * @date 2021年1月8日
	 */
	public static boolean alertColumn(String tableName,String con,ColumnMetaV2 cmV2) {
		return db.alertColumn(tableName, con, cmV2);
	}
	
	public static boolean checkAlertColumn(String tableName,String con,ColumnMetaV2 cmV2) {
		TableMetaV2 tm = db.getDBMetaV2().getTables().get(tableName);
		if(tm==null) {
			return false;
		}
		ColumnMetaV2 cm = tm.getColumns().get(con);
		if(cm==null) {
			return false;
		}
		return cm.check(cmV2);
	}
	
	
	
}
